package com.xbongbong.saas.analytical.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.ConfigConstant;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.enums.PaymentSheetTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.pro.enums.errorcodes.ImportErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.InvoiceErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.RefundErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.fund.enums.ModelTypeEnum;
import com.xbongbong.pro.formdata.pojo.SaasNeedRedundantAttrPojo;
import com.xbongbong.saas.analytical.SaasValidateAnalyticalService;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.InvoiceConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ext.ContractEntityExt;
import com.xbongbong.saas.domain.entity.ext.InvoiceEntityExt;
import com.xbongbong.saas.domain.entity.ext.PaymentEntityExt;
import com.xbongbong.saas.domain.entity.ext.PaymentSheetEntityExt;
import com.xbongbong.saas.enums.SheetAloneEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.InvoiceEnum;
import com.xbongbong.saas.enums.business.PaymentEnum;
import com.xbongbong.saas.enums.business.PaymentRelationshipEnum;
import com.xbongbong.saas.enums.business.PaymentSheetEnum;
import com.xbongbong.saas.enums.dictionary.PaymentStatusEnum;
import com.xbongbong.saas.help.FundHelp;
import com.xbongbong.saas.help.AnalyticalHelp;
import com.xbongbong.saas.help.InvoiceCommonHelp;
import com.xbongbong.saas.help.SaasDataInitHelp;
import com.xbongbong.saas.help.SaasInvoiceHelp;
import com.xbongbong.saas.help.SaveFormatHelp;
import com.xbongbong.saas.model.ContractModel;
import com.xbongbong.saas.model.FundSetModel;
import com.xbongbong.saas.model.InvoiceModel;
import com.xbongbong.saas.model.PaymentModel;
import com.xbongbong.saas.model.PaymentSheetModel;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.UserModel;
import com.xbongbong.util.InvoiceUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getDoubleFromFormData;
import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getDoubleOrDefaultFromFormData;
import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getIntegerOrDefaultFromFormData;

/**
 * @author 吴峰
 * @date 2021/07/15 17:15
 */
@Service("invoiceAnalyticalServiceImpl")
public class InvoiceValidateAnalyticalServiceImpl implements SaasValidateAnalyticalService {
    
    private static final Logger LOGGER = LoggerFactory.getLogger(InvoiceValidateAnalyticalServiceImpl.class);
    
    @Resource
    private FundHelp fundHelp;
    @Resource
    private UserModel userModel;
    @Resource
    private PaymentSheetModel paymentSheetModel;
    @Resource
    private PaymentModel paymentModel;
    @Resource
    private SaasInvoiceHelp saasInvoiceHelp;
    @Resource
    private ContractModel contractModel;
    @Resource
    private InvoiceModel invoiceModel;
    @Resource
    private FundSetModel fundSetModel;
    @Resource
    private AnalyticalHelp analyticalHelp;

    @Override
    public List<Integer> type() {
        return Arrays.asList(XbbRefTypeEnum.INVOICE.getCode());
    }

    @Override
    public void analyticalData(ValidateDataDTO validateDataDTO) throws XbbException {
        beforeSave(validateDataDTO);
    }
    
    public void beforeSave(ValidateDataDTO validateDataDTO) throws XbbException {
        try {
            boolean isNew = analyticalHelp.isNew(validateDataDTO.getDataId(), validateDataDTO.getTaskId(), validateDataDTO.getCorpid());
            JSONObject data = validateDataDTO.getData();
            Integer isImport = validateDataDTO.getIsImport();
            Integer isCover = validateDataDTO.getIsCover();
            //是覆盖导入作废的发票。直接在文档中提示错误信息
            //判断当前发票是否作废
            Integer isCancel = FastJsonHelper.getIntegerOrDefaultFromFormData(data, InvoiceEnum.IS_CANCEL.getAttr(), BasicConstant.ZERO);
            if (Objects.equals(BasicConstant.ONE, isCancel)){
                //是作废的发票，提示作废发票不允许编辑
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.INVOICE_CANCEL_NOT_EDIT);
            }

            //是覆盖导入作废的发票
            boolean invoiceFlag = Objects.equals(BasicConstant.ONE, isCover) && Objects.equals(BasicConstant.ONE, isCancel);
            if (invoiceFlag){
                throw new XbbException(ImportErrorCodeEnum.API_ERROR_235058);
            }
            JSONArray amountDetail = validateDataDTO.getAmountDetail();
            amountDetail = Objects.nonNull(amountDetail) ? amountDetail : new JSONArray();
            Boolean isPrePaymentSheet = false;
            Boolean isPrePaymentSheetUnion = false;
            Boolean invoiceCustomer = fundHelp.checkInvoiceByCustomerOrNot(data,validateDataDTO.getBusinessType());
            String corpid = validateDataDTO.getCorpid();
            Map<String, FieldAttrEntity> explainMap = validateDataDTO.getExplainMap();
            if(CollectionsUtil.isEmpty(amountDetail) && Objects.equals(isImport,BasicConstant.ZERO)){
                if(!invoiceCustomer) {
                    //兼容老数据,老数据走导入的老逻辑
                    isImport = BasicConstant.ONE;
                }
            }
            if(Objects.equals(isImport,BasicConstant.ONE)){
                //导入有些炒作进行处理
                verifyImportData(data,validateDataDTO.getCorpid(),isPrePaymentSheet);
                //这边对销项发票覆盖导入进行处理
                if(Objects.nonNull(validateDataDTO.getDataId())){
                    InvoiceEntityExt invoiceEntityExt = invoiceModel.getByKey(validateDataDTO.getDataId(), validateDataDTO.getCorpid());
                    //获得创建应收款的模式
                    Long modelType = invoiceEntityExt.getSysLong10();
                    //获取当前的应收模式
                    Long nowModelType = fundSetModel.getModelType(corpid,XbbRefTypeEnum.CRM);
                    FieldAttrEntity fieldAttrEntity = explainMap.get(InvoiceEnum.INVOICE_DATE.getAttr());
                    removeUnEditImportAttr(data,invoiceEntityExt,validateDataDTO.getBusinessType(),fieldAttrEntity,modelType,nowModelType);
                }
            }
            FieldAttrEntity fieldAttrEntity = new FieldAttrEntity();
            // 发票id 关联合同 关联回款 获取
            Long invoiceId = 0L;
            if(Objects.nonNull(validateDataDTO.getDataId()) && !isNew){
                invoiceId = validateDataDTO.getDataId();
            }

            JSONArray applyUser = FastJsonHelper.getJsonArrOrDefaultFromFormData(data,InvoiceEnum.APPLY_USER.getAttr(),null);
            Long invoiceDate = FastJsonHelper.getLongOrDefaultFromFormData(data,InvoiceEnum.INVOICE_DATE.getAttr(),0L);
            if(CollectionsUtil.isEmpty(applyUser) && !Objects.equals(isImport,BasicConstant.ONE)){
                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216050);
            }
            if(invoiceDate <= 0L){
                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216052);
            }
            //销项发票对离职人员进行过滤
            if (CollectionsUtil.isNotEmpty(applyUser) && !Objects.equals(isImport,BasicConstant.ONE)) {
                String userIdIn = applyUser.getString(0);
                if (userIdIn != null && userIdIn.length() > 0) {
                    UserEntity userEntity = userModel.getByKey(userIdIn, corpid);
                    if (Objects.isNull(userEntity)) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100065);
                    }
                }
            }
            JSONArray customerArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(data,InvoiceEnum.CUSTOMER_NAME.getAttr(),new JSONArray());
            JSONArray contractArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, InvoiceEnum.CONTRACT_ID.getAttr(), new JSONArray());
            JSONArray paymentArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, InvoiceEnum.PAYMENT_ID.getAttr(), new JSONArray());
            JSONArray paymentSheetArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(data,InvoiceEnum.PAYMENT_SHEET_ID.getAttr(),new JSONArray());

            List<Long> customerIds = new ArrayList<>();
            List<Long> contractIds = new ArrayList<>();
            List<Long> paymentIds = new ArrayList<>();
            List<Long> paymentSheetIds = new ArrayList<>();
            if(Objects.nonNull(customerArray)){
                getRefIds(customerArray,customerIds);
                if(Objects.equals(customerArray.size(),BasicConstant.ZERO)){
                    data.put(InvoiceEnum.CUSTOMER_NAME.getAttr(),null);
                }
            }
            if (Objects.nonNull(contractArray) && contractArray.size()>0) {
                getRefIds(contractArray,contractIds);
            }else {
                if(invoiceId>0L){
                    data.put(InvoiceEnum.CONTRACT_ID.getAttr(),null);
                    data.put(InvoiceEnum.CONTRACT_ID_LINK_TEXT.getAttr(),null);
                }
            }
            if(Objects.nonNull(paymentArray) && paymentArray.size()>0) {
                getRefIds(paymentArray,paymentIds);
            }else {
                if(invoiceId>0L){
                    data.put(InvoiceEnum.PAYMENT_ID.getAttr(),null);
                    data.put(InvoiceEnum.PAYMENT_ID_LINK_TEXT.getAttr(),null);
                }
            }
            if(Objects.nonNull(paymentSheetArray) && paymentSheetArray.size()>0){
                getRefIds(paymentSheetArray,paymentSheetIds);
            }else {
                if(invoiceId>0L){
                    data.put(InvoiceEnum.PAYMENT_SHEET_ID.getAttr(),null);
                    data.put(InvoiceEnum.PAYMENT_SHEET_ID_LINK_TEXT.getAttr(),null);
                }
            }
            //是否是预收款回款单发票
            if(!Objects.equals(isImport,BasicConstant.ONE)){
                isPrePaymentSheet = parsePrePaymentSheet(data);
                if(isPrePaymentSheet && paymentSheetArray.size() >= BasicConstant.TWO){
                    isPrePaymentSheetUnion = true;
                    isPrePaymentSheet = true;
                }
            }
            boolean flag = Objects.equals(validateDataDTO.getIsImport(), BasicConstant.ONE) && (isPrePaymentSheet || isPrePaymentSheetUnion);
            if(flag){
                //如果导入预收款回款单
                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216033);
            }
            // 退货退款校验
            verifyReturnedContract(contractIds, corpid, paymentArray,paymentSheetArray);
            //现在已经剔除了开票金额为0的关联单据 这一步 不需要 关联单据可开票为0判断
            //checkRefNotInvoiceAmount(data,totalMoney,isImport);
            // 把关联业务传来的jsonArray变成两个字段保存到数据库
            formatInvoiceLinkBusiness4Save(data);
            // 原始发票id 开票金额 开票金额解释 客户id获取
            SaveFormatHelp.formatLinkBusiness4SaveByArray(data, InvoiceEnum.ORIGIN_ID.getAttr(), InvoiceEnum.ORIGIN_ID_LINK_TEXT.getAttr(), InvoiceEnum.ORIGIN_ID.getFieldType());
            Long originId = FastJsonHelper.getLongOrDefaultFromFormData(data, InvoiceEnum.ORIGIN_ID.getAttr(), 0L);
            Long customerId = FastJsonHelper.getLongFromFormData(data, InvoiceEnum.CUSTOMER_NAME.getAttr());
            Long editInvoiceId = null;
            if(invoiceId > 0){
                editInvoiceId = invoiceId;
            }
            // 判断是红冲发票还是正常开票
            InvoiceCommonHelp.getMinusAmountFormRedInvoice(data,amountDetail,originId,isImport,validateDataDTO.getBusinessType());
            Double totalMoney = getDoubleOrDefaultFromFormData(data, InvoiceEnum.TOTAL_MONEY.getAttr(), 0.0D);
            // 红冲和正常发票金额校验
            verifyInvoiceMoney(data,originId, corpid, totalMoney,editInvoiceId,isImport);
            // 是否合同合并开票
            boolean isContractUnion = false;
            // 是否回款合并开票
            boolean isPaymentUnion = false;
            // 是否选择合同
            boolean isHasContract = false;
            // 是否选择了应收款
            boolean isHasPayment = false;
            //是否选择了回款单
            boolean isHasPaymentSheet = false;
            //是否回款单合并开票
            boolean isPaymentSheetUnion = false;
            if (Objects.nonNull(customerId) && Objects.nonNull(contractArray) && contractArray.size() > 0) {
                isHasContract = true;
                if (contractArray.size() > BasicConstant.ONE) {
                    isContractUnion = true;
                }
                if (Objects.nonNull(paymentArray) && paymentArray.size() > BasicConstant.ZERO) {
                    isHasPayment = true;
                    if (paymentArray.size() > BasicConstant.ONE) {
                        //有两个合同时只有一个应收款或回款单应该将合同合并开票置成false
                        isContractUnion = false;
                        isPaymentUnion = true;
                    }
                }
                if(paymentSheetArray.size() > BasicConstant.ZERO){
                    isHasPaymentSheet = true;
                    if(paymentSheetArray.size() > BasicConstant.ONE){
                        isContractUnion = false;
                        isPaymentSheetUnion = true;
                    }
                }
            }else if(Objects.nonNull(customerId)){
                if(paymentSheetArray.size() > BasicConstant.ZERO){
                    isHasPaymentSheet = true;
                    if(paymentSheetArray.size() > BasicConstant.ONE){
                        isPaymentSheetUnion = true;
                        if(isPrePaymentSheet){
                            isPaymentSheetUnion = false;
                            isPrePaymentSheetUnion = true;
                        }
                    }
                }
            }
            SaasNeedRedundantAttrPojo saasNeedRedundantAttrPojo = new SaasNeedRedundantAttrPojo();
            SaasNeedRedundantAttrPojo saasNeedPoJo = validateDataDTO.getSaasNeedRedundantAttrPoJo();
            saasNeedRedundantAttrPojo.setHasContract(isHasContract);
            saasNeedRedundantAttrPojo.setHasPayment(isHasPayment);
            saasNeedRedundantAttrPojo.setHasPaymentSheet(isHasPaymentSheet);
            saasNeedRedundantAttrPojo.setContractUnion(isContractUnion);
            saasNeedRedundantAttrPojo.setPaymentUnion(isPaymentUnion);
            saasNeedRedundantAttrPojo.setPaymentSheetUnion(isPaymentSheetUnion);
            saasNeedRedundantAttrPojo.setPrePaymentSheet(isPrePaymentSheet);
            saasNeedRedundantAttrPojo.setPrePaymentSheetUnion(isPrePaymentSheetUnion);
            if (Objects.nonNull(saasNeedPoJo)){
                saasNeedRedundantAttrPojo.setInvoiceSpecialParamPojo(saasNeedPoJo.getInvoiceSpecialParamPojo());
            }
            boolean hasContractOrPayment = (isHasPayment || isHasPaymentSheet || isHasContract) && originId == 0L;
            if (hasContractOrPayment) {
                List<Long> refIds = null;
                if(isHasPayment){
                    refIds = paymentIds;
                }
                if(isHasPaymentSheet){
                    refIds = paymentSheetIds;
                }
                Map<String,Object> relationMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                relationMap.put("contractNum",contractIds.size());
                relationMap.put("paymentNum",paymentIds.size());
                relationMap.put("paymentSheetNum",paymentSheetIds.size());
                //先删掉一些不需要的关联
                if(!Objects.equals(isImport,BasicConstant.ONE)) {
                    //移除掉非法操作的合并开票
                    InvoiceUtil.verifyUnionInvoiceMoney(saasNeedRedundantAttrPojo, relationMap, amountDetail, data, originId, contractIds, refIds,XbbRefTypeEnum.INVOICE.getCode());
                }
                relationMap = saasInvoiceHelp.getRelationMapForJudgeMoney(isHasPaymentSheet,isPrePaymentSheet,isPrePaymentSheetUnion,isHasPayment, corpid, contractIds, refIds);
                if(Objects.equals(corpid,"dingc45df9402649cb4635c2f4657eb6378f")){
                    LOGGER.warn("销项发票合并开票关键日志，getRelationMapForJudgeMoney(),relationMap:{},amountDetail:{}",relationMap,amountDetail);
                }
                // 审批、新建、编辑、还原 金额判断
                saasInvoiceHelp.invoiceAmountJudgment(corpid, invoiceId, totalMoney, relationMap,isImport,isCover,BasicConstant.ZERO,amountDetail);
            }
            if(originId > 0L && !Objects.equals(isImport,BasicConstant.ONE)){
                List<Long> refIds = null;
                if(isHasPayment){
                    refIds = paymentIds;
                }
                if(isHasPaymentSheet){
                    refIds = paymentSheetIds;
                }
                Map<String,Object> relationMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                relationMap.put("contractNum",contractIds.size());
                relationMap.put("paymentNum",paymentIds.size());
                relationMap.put("paymentSheetNum",paymentSheetIds.size());
                InvoiceUtil.verifyUnionInvoiceMoney(saasNeedRedundantAttrPojo,relationMap,amountDetail,data,originId,contractIds,refIds,XbbRefTypeEnum.INVOICE.getCode());
            }
            for (Map.Entry<String,Object> entry : SaasDataInitHelp.initInvoice().entrySet()){
                SaasDataInitHelp.antDataSet(data,entry.getKey(),entry.getValue());
            }
            validateDataDTO.setData(data);
            SaasNeedRedundantAttrPojo saasNeedRedundantAttrPojoOld = validateDataDTO.getSaasNeedRedundantAttrPoJo();
            if (saasNeedRedundantAttrPojoOld != null && saasNeedRedundantAttrPojoOld.getRefundId() != null) {
                data.put(PaasConstant.REFUND_ID, saasNeedRedundantAttrPojoOld.getRefundId());
            }
            if (CollectionsUtil.isNotEmpty(amountDetail)) {
                saasNeedRedundantAttrPojo.setAmountDetail(amountDetail);
            }
            validateDataDTO.setSaasNeedRedundantAttrPoJo(saasNeedRedundantAttrPojo);
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOGGER.error("invoiceAnalyticalServiceImpl.beforeSave error", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }

    private void getRefIds(JSONArray refIds,List<Long> ids){
        if(Objects.nonNull(refIds)){
            refIds.forEach((obj) ->{
                JSONObject refObjson = (JSONObject) obj;
                Long id = refObjson.getLong(StringConstant.SAAS_LINK_BUSINESS_ID) == null ? 0L : refObjson.getLong(StringConstant.SAAS_LINK_BUSINESS_ID);
                ids.add(id);
            });
        }
    }

    private Boolean parsePrePaymentSheet(JSONObject data){
        if(Objects.nonNull(data.getJSONArray(InvoiceEnum.PAYMENT_SHEET_ID.getAttr()))) {
            if(data.getJSONArray(InvoiceEnum.PAYMENT_SHEET_ID.getAttr()).size() >0) {
                JSONObject paymentSheetObject = data.getJSONArray(InvoiceEnum.PAYMENT_SHEET_ID.getAttr()).getJSONObject(0);
                String paymentSheetType = paymentSheetObject.getString(InvoiceConstant.PAYMENT_SHEET_TYPE);
                if (Objects.equals(paymentSheetType, PaymentSheetTypeEnum.PREPAYMENT.getCode())) {
                    return true;
                }
            }
        }
        return false;
    }

    public void verifyImportData(JSONObject data,String corpid,Boolean isPrePaymentSheet) throws XbbException{
        if(Objects.nonNull(data)){
            if(Objects.isNull(data.getString(InvoiceEnum.PAYMENT_RELATIONSHIP.getAttr()))){
                //当回款计划或者回款单任意存在一个的时候  类型必填（产品讨论结果）
                if(CollectionsUtil.isNotEmpty(data.getJSONArray(InvoiceEnum.PAYMENT_ID.getAttr())) || CollectionsUtil.isNotEmpty(data.getJSONArray(InvoiceEnum.PAYMENT_SHEET_ID.getAttr()))){
                    throw  new XbbException(InvoiceErrorCodeEnum.API_ERROR_216041);
                }
                if(CollectionsUtil.isNotEmpty(data.getJSONArray(InvoiceEnum.PAYMENT_ID.getAttr()))){
                    data.put(InvoiceEnum.PAYMENT_RELATIONSHIP.getAttr(), PaymentRelationshipEnum.PAYMENT.getCode());
                }
                if(CollectionsUtil.isNotEmpty(data.getJSONArray(InvoiceEnum.PAYMENT_SHEET_ID.getAttr()))){
                    data.put(InvoiceEnum.PAYMENT_RELATIONSHIP.getAttr(),PaymentRelationshipEnum.PAYMENT_SHEET.getCode());
                }
            }
            //三者都在的时候不再给默认值，以回款类型为标准  （产品讨论结果）2020年1月10日15:42:45
/*            if(Objects.nonNull(data.getString(InvoiceEnum.PAYMENT_RELATIONSHIP.getAttr()))
                    && Objects.nonNull(data.getJSONArray(InvoiceEnum.PAYMENT_ID.getAttr())) && Objects.nonNull(data.getJSONArray(InvoiceEnum.PAYMENT_SHEET_ID.getAttr()))){
                data.put(InvoiceEnum.PAYMENT_RELATIONSHIP.getAttr(),PaymentRelationshipEnum.PAYMENT.getCode());
            }*/
            if(Objects.nonNull(data.getString(InvoiceEnum.PAYMENT_RELATIONSHIP.getAttr()))){
                if(Objects.equals(PaymentRelationshipEnum.PAYMENT.getCode(),data.getString(InvoiceEnum.PAYMENT_RELATIONSHIP.getAttr()))){
                    data.remove(InvoiceEnum.PAYMENT_SHEET_ID.getAttr());
                }else if(Objects.equals(PaymentRelationshipEnum.PAYMENT_SHEET.getCode(),data.getString(InvoiceEnum.PAYMENT_RELATIONSHIP.getAttr()))){
                    data.remove(InvoiceEnum.PAYMENT_ID.getAttr());
                }
            }

            if(Objects.isNull(data.getJSONArray(InvoiceEnum.CONTRACT_ID.getAttr()))){
                if(Objects.nonNull(data.getJSONArray(InvoiceEnum.PAYMENT_SHEET_ID.getAttr()))){
                    isPrePaymentSheet = true;
                }
                if(Objects.nonNull(data.getJSONArray(InvoiceEnum.PAYMENT_ID.getAttr()))){
                    throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216040);
                }
            }
            if(Objects.equals(data.getString(InvoiceEnum.PAYMENT_RELATIONSHIP.getAttr()),PaymentRelationshipEnum.PAYMENT.getCode()) && Objects.nonNull(data.getJSONArray(InvoiceEnum.PAYMENT_ID.getAttr()))){
                JSONArray dataArray = data.getJSONArray(InvoiceEnum.PAYMENT_ID.getAttr());
                Set<Long> idSet = new HashSet<>();
                Map<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                if(CollectionsUtil.isNotEmpty(dataArray)) {
                    for (int i = 0; i < dataArray.size(); i++) {
                        JSONObject dataObject = dataArray.getJSONObject(i);
                        if (Objects.nonNull(dataObject)) {
                            idSet.add(dataObject.getLong(BasicConstant.ID));
                        }
                    }
                    param.put("corpid",corpid);
                    param.put("idIn",idSet);
                    param.put("del",BasicConstant.ZERO);
                    List<PaymentEntityExt> paymentEntityExtList = paymentModel.findEntitys(param);
                    if(CollectionsUtil.isNotEmpty(paymentEntityExtList)) {
                        for (PaymentEntityExt paymentEntityExt : paymentEntityExtList) {
                            String status = FastJsonHelper.getStringOrDefaultFromFormData(paymentEntityExt.getData(), PaymentEnum.STATUS.getAttr(), PaymentStatusEnum.UN_RECEIVABLES.getCode());
                            Integer isRed = getIntegerOrDefaultFromFormData(paymentEntityExt.getData(), PaymentEnum.IS_RED.getAttr(), BasicConstant.ZERO);
                            boolean isBad = Objects.equals(status, PaymentStatusEnum.BAD_DEBT.getCode()) || Objects.equals(status, PaymentStatusEnum.PARTIAL_BAD_DEBT.getCode());
                            if (Objects.equals(isRed, BasicConstant.ONE) || isBad) {
                                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216017);
                            }
                        }
                    }
                }
            }
            if(Objects.equals(data.getString(InvoiceEnum.PAYMENT_RELATIONSHIP.getAttr()),PaymentRelationshipEnum.PAYMENT_SHEET.getCode()) && Objects.nonNull(data.getJSONArray(InvoiceEnum.PAYMENT_SHEET_ID.getAttr()))){
                JSONArray dataArray = data.getJSONArray(InvoiceEnum.PAYMENT_SHEET_ID.getAttr());
                Set<Long> idSet = new HashSet<>();
                Set<String> uuids = new HashSet<>();
                JSONArray totalArray = new JSONArray();
                Map<String,JSONArray> paymentSheetMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<Long,String> uuidMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                if(CollectionsUtil.isNotEmpty(dataArray)) {
                    for (int i=0;i < dataArray.size(); i++) {
                        JSONObject dataObject = dataArray.getJSONObject(i);
                        if(Objects.nonNull(dataObject)){
                            idSet.add(dataObject.getLong(BasicConstant.ID));
                        }
                    }
                    param.put("corpid",corpid);
                    param.put("idIn",idSet);
                    param.put("del",BasicConstant.ZERO);
                    List<PaymentSheetEntityExt> paymentSheetEntityExtList = paymentSheetModel.findEntitys(param);
                    for(PaymentSheetEntityExt paymentSheetEntityExt : paymentSheetEntityExtList) {
                        if (Objects.nonNull(paymentSheetEntityExt.getUuid())) {
                            uuids.add(paymentSheetEntityExt.getUuid());
                            uuidMap.put(paymentSheetEntityExt.getId(), paymentSheetEntityExt.getUuid());
                        }
                        if (Objects.equals(paymentSheetEntityExt.getAlone(), SheetAloneEnum.CHILD.getCode())) {
                            throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216042);
                        }
                        String status = FastJsonHelper.getStringOrDefaultFromFormData(paymentSheetEntityExt.getData(), PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), PaymentSheetTypeEnum.WRITE_OFF.getCode());
                        boolean isBad = PaymentSheetTypeEnum.isBad(status);
                        boolean isRed = PaymentSheetTypeEnum.isRed(status);
                        boolean isWriteOffPrePaymentSheet= Objects.equals(status,PaymentSheetTypeEnum.WRITE_OFF_PREPAYMENT.getCode());
                        if(isRed || isBad){
                            throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216017);
                        }
                        if(isWriteOffPrePaymentSheet){
                            throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216051);
                        }
                    }
                    List<PaasFormDataEntityExt> paymentSheetEntityExts = fundHelp.getChildEsDataListByParentUuids(XbbRefTypeEnum.PAYMENT_SHEET, corpid,uuids,null,null);
                    paymentSheetEntityExts.forEach(paymentSheetEntityExt -> {
                        if(Objects.nonNull(paymentSheetEntityExt)) {
                            if(paymentSheetMap.containsKey(paymentSheetEntityExt.getUuid())) {
                                JSONObject jsonObject = new JSONObject();
                                jsonObject.put(BasicConstant.ID,paymentSheetEntityExt.getId());
                                jsonObject.put(BasicConstant.NAME,paymentSheetEntityExt.getSerialNo());
                                paymentSheetMap.get(paymentSheetEntityExt.getUuid()).add(jsonObject);
                            }else {
                                JSONObject jsonObject = new JSONObject();
                                jsonObject.put(BasicConstant.ID,paymentSheetEntityExt.getId());
                                jsonObject.put(BasicConstant.NAME,paymentSheetEntityExt.getSerialNo());
                                JSONArray paymentSheetArray = new JSONArray();
                                paymentSheetArray.add(jsonObject);
                                paymentSheetMap.put(paymentSheetEntityExt.getUuid(),paymentSheetArray);
                            }
                        }
                    });
                    for (int i=0;i < dataArray.size(); i++) {
                        JSONObject dataObject = dataArray.getJSONObject(i);
                        if(Objects.nonNull(dataObject)){
                            Long id = dataObject.getLong(BasicConstant.ID);
                            String uuid = uuidMap.get(id);
                            if(Objects.nonNull(paymentSheetMap.get(uuid))){
                                totalArray.addAll(paymentSheetMap.get(uuid));
                            }else {
                                totalArray.add(dataObject);
                            }
                        }
                    }
                    dataArray.clear();
                    dataArray.addAll(totalArray);
                    data.put(InvoiceEnum.PAYMENT_SHEET_ID.getAttr(),dataArray);
                }
            }
        }
    }
    /**
     * 把关联业务传来的jsonArray变成两个字段保存到数据库
     *
     * @param data 数据
     * @throws XbbException 异常
     */
    private void formatInvoiceLinkBusiness4Save(JSONObject data) throws XbbException {
        SaveFormatHelp.formatLinkBusiness4SaveByArray(data, InvoiceEnum.CUSTOMER_NAME.getAttr(), InvoiceEnum.CUSTOMER_NAME_LINK_TEXT.getAttr(), InvoiceEnum.CUSTOMER_NAME.getFieldType());
        SaveFormatHelp.formatLinkBusiness4SaveByArray(data, InvoiceEnum.CONTRACT_ID.getAttr(), InvoiceEnum.CONTRACT_ID_LINK_TEXT.getAttr(), InvoiceEnum.CONTRACT_ID.getFieldType());
        SaveFormatHelp.formatLinkBusiness4SaveByArray(data, InvoiceEnum.PAYMENT_ID.getAttr(), InvoiceEnum.PAYMENT_ID_LINK_TEXT.getAttr(), InvoiceEnum.PAYMENT_ID.getFieldType());
        SaveFormatHelp.formatLinkBusiness4SaveByArray(data, InvoiceEnum.PAYMENT_SHEET_ID.getAttr(),InvoiceEnum.PAYMENT_SHEET_ID_LINK_TEXT.getAttr(),InvoiceEnum.PAYMENT_SHEET_ID.getFieldType());
    }

    /**
     * 校验退货退款
     *
     * @param contractIds  合同id
     * @param corpid       公司id
     * @param paymentArray 回款
     * @throws XbbException 异常
     */
    private void verifyReturnedContract(List<Long> contractIds, String corpid, JSONArray paymentArray,JSONArray paymentSheetArray) throws XbbException {
        if (!contractIds.isEmpty()) {
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put(ParameterConstant.ID_IN, contractIds);
            param.put(ParameterConstant.CORPID, corpid);
            Integer redCount = contractModel.getCountByOneCondition(ContractEnum.IS_RED.getAttr(), "1", param);
            if (redCount > 0) {
                throw new XbbException(RefundErrorCodeEnum.API_ERROR_215013);
            }
        }
    }

    /**
     * 校验开票金额
     *
     * @param originId        原始id
     * @param corpid          公司id
     * @param totalMoney      开票金额
     * @param editInvoiceId 解释
     * @throws XbbException 校验异常
     * @author feng.zheng
     * @date 2019/2/27 10:28
     */
    private void verifyInvoiceMoney(JSONObject data,Long originId, String corpid, Double totalMoney,Long editInvoiceId,Integer isImport) throws XbbException {
        if (Objects.equals(Math.abs(totalMoney), BasicConstant.ZERO_DOUBLE)) {
            throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216015);
        }
        InvoiceEntityExt originInvoice;
        if (originId > 0) {
            if (totalMoney > BasicConstant.ZERO_DOUBLE) {
                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216018);
            }
            originInvoice = invoiceModel.getByKey(originId, corpid);
            if (originInvoice == null) {
                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216011);
            }
            double redTotalMoney = 0;
            if(Objects.nonNull(editInvoiceId)){
                redTotalMoney = saasInvoiceHelp.getRedTotalMoneyByEdit(originId,corpid,editInvoiceId);
            }else {
                redTotalMoney = invoiceModel.getRedTotalMoney(originId, corpid);
            }
            Double originTotalMoney = getDoubleFromFormData(originInvoice.getData(), InvoiceEnum.TOTAL_MONEY.getAttr());
            if (Arith.sub(Math.abs(redTotalMoney + totalMoney), originTotalMoney) > ConfigConstant.amountAccuracy) {
                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216013);
            }
        } else {
            if (totalMoney < BasicConstant.ZERO_DOUBLE) {
                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216020);
            }
        }
    }


    /**
     * 销项发票：删除覆盖导入不能编辑的字段
     * @param data  前端传的json数据
     * @param invoiceEntity 数据原始数据
     * @param businessType 业务类型
     * @param modelType    创建时应收模式
     * @param nowModelType 当前应收模式
     */
    private void removeUnEditImportAttr(JSONObject data, PaasFormDataEntity invoiceEntity, Integer businessType, FieldAttrEntity fieldAttrEntity, Long modelType, Long nowModelType) throws XbbException {
        JSONObject originData = invoiceEntity.getData();
        String corpid = invoiceEntity.getCorpid();
        Integer isCancel = FastJsonHelper.getIntegerOrDefaultFromFormData(originData, InvoiceEnum.IS_CANCEL.getAttr(), BasicConstant.ZERO);
        List<String> invoiceShouldRemoveFieldList = new ArrayList<>();
        //1、关联合同字段不允许覆盖导入
        invoiceShouldRemoveFieldList.add(InvoiceEnum.CONTRACT_ID.getAttr());
        //2、处理开票模式的发票不允许编辑开票日期，包括作废发票，所以覆盖导入的时候过滤掉
        boolean isFilterInvoiceDate =  Objects.equals(XbbRefTypeEnum.INVOICE.getCode(), businessType)
                && (Objects.equals(nowModelType, ModelTypeEnum.INVOICE.getCode())
                || (Objects.nonNull(modelType) && Objects.equals(modelType, ModelTypeEnum.INVOICE.getCode()))
                || Objects.equals(fieldAttrEntity.getEditable(),BasicConstant.ZERO)
                || Objects.equals(isCancel,BasicConstant.ONE));
        if (isFilterInvoiceDate){
            invoiceShouldRemoveFieldList.add(InvoiceEnum.INVOICE_DATE.getAttr());
        }
        for(String field : invoiceShouldRemoveFieldList){
            for (String key : data.keySet()) {
                if (Objects.equals(key,field)) {
                    if(Objects.equals(key,InvoiceEnum.CONTRACT_ID.getAttr())){
                        //从源数据获取关联合同是个jsonArray里面是字符串,要将它封装成jsonObject
                        JSONArray jsonArray = new JSONArray();
                        JSONObject jsonObject = new JSONObject();
                        JSONArray originJsonArray = FastJsonHelper.getJsonArrFromFormData(originData, key);
                        if(CollectionsUtil.isNotEmpty(originJsonArray)){
                            String contractId = originJsonArray.getString(0);
                            ContractEntityExt contractEntityExt = contractModel.getByKey(Long.parseLong(contractId), corpid);
                            //获取合同的id和编号
                            jsonObject.put(StringConstant.SAAS_LINK_BUSINESS_ID,contractId);
                            jsonObject.put(StringConstant.SAAS_LINK_BUSINESS_NAME,contractEntityExt.getSerialNo());
                            jsonArray.add(jsonObject);
                            data.put(key, jsonArray);
                        } else {
                            data.put(key, originJsonArray);
                        }
                    }else{
                        data.put(key, originData.get(key));
                    }
                }
            }
        }
    }


}
